package geo.obj;

import geo.math.GMath;
import geo.math.PhiFunction;

import java.awt.Color;
import java.awt.Polygon;
import java.util.ArrayList;
import gui.panels.*;

public class PhiObject implements IObject {
	private double[] _x;
	private double[] _y;
	private double _px;
	private double _py;
	private double _phi;
	private String _name;
	private ArrayList<Triangle> _tlist;
	private Color _color = Color.BLACK;
	public boolean work = true;
	
	public boolean isWork() {
		return work;
	}

	public void setWork(boolean work) {
		this.work = work;
	}

	PhiFunction _unnamed_PhiFunction_;
	DomainDrawPanel _unnamed_DomainDrawPanel_;
	ObjectDrawPanel _unnamed_ObjectDrawPanel_;
	
	public PhiObject(){
		
	}
	
	public PhiObject(double[] x, double[] y, double px, double py, double phi, String name){
		this._x = x;
		this._y = y;
		this._px = px;
		this._py = py;
		this._phi = phi;
		this._name = name;
		if(!check()) System.err.println("ERROR: incorrect length of arrays of coordinates!");
		wayCorrection();
	}
	
	public PhiObject(double[] x, double[] y, double px, double py, double phi){
		this._x = x;
		this._y = y;
		this._px = px;
		this._py = py;
		this._phi = phi;
		if(!check()) System.err.println("ERROR: incorrect length of arrays of coordinates!");
		wayCorrection();
	}
	
	/**
	 * checks length of x and y arrays
	 * @return
	 */
	private boolean check(){
		if (_x.length == _y.length) return true;
		else return false;
	}

	public void setX(double[] aX) {
		this._x = aX;
	}

	public double[] getX() {
		return this._x;
	}

	public void setY(double[] aY) {
		this._y = aY;
	}

	public double[] getY() {
		return this._y;
	}

	public void setPx(double aPx) {
		this._px = aPx;
	}

	public double getPx() {
		return this._px;
	}

	public void setPy(double aPy) {
		this._py = aPy;
	}

	public double getPy() {
		return this._py;
	}

	public double getPhi() {
		return this._phi;
	}

	public ArrayList<Triangle> getTrianglelist() {
		return this._tlist;
	}

	public void setColor(Color aColor) {
		this._color = aColor;
	}

	public Color getColor() {
		return this._color;
	}
	
	public String getName(){
		return _name;
	}
	
	public void setName(String name){
		this._name = name;
	}
	
	/**
	 * This method returns count of vertexes in object
	 * @return value of vertexes
	 */
	public int size(){
		return _x.length;
	}
	
	/**
	 * This method moves object by some value of x and y
	 */
	public boolean translate(double aX, double aY) {
		for(int i = 0; i < size(); i++){
			_x[i] += aX;
		}
		for(int i = 0; i < size(); i++){
			_y[i] += aY;
		}
		_px += aX;
		_py += aY;
		
		return true;
	}
	
	/**
	 * Moves object to pole coordinates of x and y
	 */
	public boolean moveTo(double x, double y) {
		double xl = GMath.length(_px, _py, x, _py);
		double yl = GMath.length(x, y, x, _py);
		
		if(x < _px) xl *= -1;
		if(y < _py) yl *= -1;
		
		translate(xl, yl);
		return true;
		
	}

	public double culcSpace() {
		_tlist = GMath.triangulate(this);
		double sq = 0;
		for (int i = 0; i < _tlist.size(); i++){
			sq += _tlist.get(i).culcSpace();
		}
		return sq;
	}

	/**
	 * Returns true if point is on object border 
	 */
	public boolean onBorder(double aX, double aY) {
		for(int i = 0; i < size() - 1; i++){
			if (GMath.isOnLine(aX, aY , _x[i], _y[i], _x[i+1], _y[i+1])) return true;
		}
		if(GMath.isOnLine(aX, aY, _x[size()-1], _y[size()-1], _x[0], _y[0])) return true;
		return false;
	}
	
	public boolean inside(double aX, double aY) {
		Polygon p = new Polygon(getIntX(), getIntY(), size());
		if (p.contains(aX, aY)) return true;
		return false;
	}

	public boolean rotate(double aAngle) {
		
		for(int i = 0; i < size(); i++){
			 double  c[] = GMath.rotate(_x[i] - _px, _y[i] - _py, aAngle);
			 _x[i] = c[0] + _px;
			 _y[i] = c[1] + _py;
		}
		
		return true;
	}
	
	/**
	 * returns rounded to integer coordinates of x
	 */
	public int[] getIntX(){
		int[]x = new int[size()];
		for (int i = 0; i < size(); i++){
			x[i] = (int)_x[i];
		}
		return x;
	}
	
	/**
	 * returns rounded to integer coordinates of y
	 * @return
	 */
	public int[] getIntY(){
		int[]y = new int[size()];
		for (int i = 0; i < size(); i++){
			y[i] = (int)_y[i];
		}
		return y;
	}
	
	public Polygon poly(){
		Polygon p = new Polygon(getIntX(), getIntY(), size());
		return p;
	}
	
	/**
	 * checks way of object
	 * @return
	 */
	private boolean leftsided(){
		int n = 0;
		double ym = _y[0];
		for(int i = 0; i < size() - 2; i++){
			if (_y[i] < ym){
				ym = _y[i];
				n = i;
			}
		}
		int n1 = n - 1;
		int n2 = n + 1;
		if(n == 0) n1 = size() - 1;
		if(n == size() - 1) n2 = 0;
		
		if(GMath.positiveVectMult(_x[n1], _y[n1], _x[n], _y[n], _x[n2], _y[n2])) return true;
		return false;
	}
	
	/**
	 * way correction
	 */
	private void wayCorrection() {
		double x[] = (double[])_x.clone();
		double y[] = (double[])_y.clone();
		
		if (!leftsided()){
			for(int i = size() - 1, j = 0; i >= 0 ; i--, j++){
				_x[j] = x[i];
				_y[j] = y[i];
			}	
		}
	}
	
	public boolean trg_test(){
		if (GMath.selfIntersect(this)) return true;
		return false;
	}
	
	public void trg(){
		_tlist = (ArrayList<Triangle>) GMath.triangulate(this).clone(); //may have mistake
	}
	
	public int getIntPx(){
		return (int)_px;
	}
	
	public int getIntPy(){
		return (int)_py;
	}
	
	public boolean intersect(PhiObject g){
		
		Polygon p1 = new Polygon(getIntX(), getIntY(), size());
		Polygon p2 = new Polygon(g.getIntX(), g.getIntY(), g.size());
		
		for(int i = 0; i < g.size(); i++){
			if (p1.contains(g.getIntX()[i], g.getIntY()[i])) return true;
		}
		
		for(int i = 0; i < this.size(); i++){
			if (p2.contains(this.getIntX()[i], this.getIntY()[i])) return true;
		}
		
		return false;
	}
}